package com.packenius.library.xspdf;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;

/**
 * Content for all commands via use()-method.
 * 
 * @author Christian Packenius, 2013.
 */
public class XSUse {
  /**
   * XSPDF document to work with.
   */
  private final XSPDF xsPDF;

  /**
   * Constructor.
   * 
   * @param xsPDF
   */
  public XSUse(XSPDF xsPDF) {
    this.xsPDF = xsPDF;
  }

  /**
   * Translate use() method call.
   * 
   * @param parms Parameters of use() method call.
   * @throws IOException
   */
  public void use(Object[] parms) throws IOException {
    for (int i = 0, count = parms.length; i < count;) {
      Object parm = parms[i];
      i++;
      if (parm instanceof XSFontType) {
        i = useFont(i, count, (XSFontType) parm, parms);
      } else if (parm instanceof XSFontParameter) {
        xsPDF.setFontParameters((XSFontParameter) parm);
      } else if (parm instanceof XSPageSize) {
        i = usePageSize(i, count, (XSPageSize) parm, parms);
      } else if (parm instanceof Dimension) {
        Dimension dim = (Dimension) parm;
        i = usePageSize(i, count, new XSPageSize(dim.width, dim.height), parms);
      } else if (parm instanceof XSSpecials) {
        i = useSpecials(i, (XSSpecials) parm);
      } else if (parm instanceof XSContentEncoding) {
        i = useContentEncoding(i, (XSContentEncoding) parm);
      } else if (parm instanceof String) {
        i = useStringForPrinting(i, (String) parm);
      } else if (parm instanceof File) {
        xsPDF.createPdf((File) parm);
      } else if (parm instanceof OutputStream) {
        xsPDF.createPdf((OutputStream) parm);
      } else if (parm instanceof XSAlignment) {
        xsPDF.setAlignment((XSAlignment) parm);
      } else if (parm instanceof Color) {
        i = useColor(i, (Color) parm, parms);
      } else if (parm instanceof XSTextRenderingMode) {
        xsPDF.setTextRenderMode((XSTextRenderingMode) parm);
      } else if (parm instanceof XSTextFormattingMode) {
        xsPDF.setTextFormattingMode((XSTextFormattingMode) parm);
      } else if (parm instanceof XSTextParagraphIndentation) {
        i = useTextParagraphIndentation(i, (XSTextParagraphIndentation) parm, parms);
      } else if (parm instanceof BufferedImage) {
        i = useBufferedImage(i, (BufferedImage) parm, parms);
      } else if (parm instanceof XSPageMargin) {
        i = usePageMargin(i, (XSPageMargin) parm);
      } else if (parm instanceof XSUnitType) {
        i = useUnitType(i, (XSUnitType) parm, parms);
      } else if (parm instanceof XSPageMode) {
        xsPDF.setPageMargin((XSPageMargin) parm);
      } else {
        throw new XSPdfException("Unknown or illegal parameter usage in use()[" + i + "]: " + parm.getClass().getName()
            + " - " + parm.toString() + "!");
      }
    }
  }

  private int useUnitType(int i, XSUnitType unitType, Object[] parms) {
    double factor = 1.0;
    if (i < parms.length) {
      Double num = getIfNumeric(parms[i]);
      if (num != null) {
        i++;
        factor = num;
      }
    }
    xsPDF.setUnitType(unitType, factor);
    return i;
  }

  // private static Double getIfNumeric(Object parm) {
  // if (parm instanceof Double) {
  // return (Double) parm;
  // }
  // if (parm instanceof Float) {
  // return (double) (Float) parm;
  // }
  // if (parm instanceof Integer) {
  // return (double) (Integer) parm;
  // }
  // if (parm instanceof Short) {
  // return (double) (Short) parm;
  // }
  // if (parm instanceof Byte) {
  // return (double) (Byte) parm;
  // }
  // return null;
  // }

  private int usePageMargin(int i, XSPageMargin parm) {
    if (xsPDF.currentPage != null) {
      throw new XSPdfException("Please set page margin before filling document with content!");
    }
    if (!xsPDF.standardColumns.isEmpty()) {
      throw new XSPdfException("Please set page margin before filling document with columns!");
    }
    xsPDF.setPageMargin(parm);
    return i;
  }

  private int useBufferedImage(int i, BufferedImage parm, Object[] parms) {
    double[] nums = new double[5];
    String[] nps = { "x coordinate", "y coordinate", "width", "height", "margin" };
    for (int k = 0; k < 5; k++) {
      Double num = null;
      if (i < parms.length) {
        num = getIfNumeric(parms[i]);
      }
      if (num == null) {
        throw new XSPdfException("Missing " + nps[k] + " for image!");
      }
      nums[k] = num;
      i++;
    }
    xsPDF.setImage(parm, nums[0], nums[1], nums[2], nums[3], nums[4]);
    return i;
  }

  private int useColor(int i, Color parm, Object[] parms) {
    xsPDF.setTextFillColor(parm);
    if (i < parms.length && parms[i] instanceof Color) {
      xsPDF.setTextStrokeColor((Color) parms[i]);
      i++;
    }
    return i;
  }

  private int useTextParagraphIndentation(int i, XSTextParagraphIndentation parm, Object[] parms) {
    int spaceCount = 1;
    switch (parm) {
    case NoIndentation:
      spaceCount = 0;
      break;
    case IndentationSpace:
      if (i < parms.length && parms[i] instanceof Integer) {
        spaceCount = (Integer) parms[i];
        i++;
      }
      break;
    }
    xsPDF.setTextParagraphIndentationSpaces(spaceCount);
    return i;
  }

  private int useFont(int i, int count, XSFontType parm, Object... parms) {
    xsPDF.setFontFamily(parm);
    while (i < count) {
      Double fontSize = getIfNumeric(parms[i]);
      if (fontSize != null) {
        xsPDF.setFontSize(fontSize);
        i++;
      } else if (parms[i] instanceof XSFontParameter) {
        xsPDF.setFontParameters((XSFontParameter) parms[i]);
        i++;
      } else {
        break;
      }
    }
    return i;
  }

  private int usePageSize(int i, int count, XSPageSize parm, Object... parms) {
    if (i < count) {
      if (parms[i].equals(XSSpecials.Rotate)) {
        parm = parm.rotate();
        i++;
      }
    }
    xsPDF.setPageSize(parm);
    return i;
  }

  private int useSpecials(int i, XSSpecials parm) {
    XSDimension currentPageSize;
    double currentUnitFactor = xsPDF.currentUnitFactor;
    switch (parm) {
    case Rotate:
      xsPDF.rotatePage();
      break;
    case NewPage:
      xsPDF.newPage();
      break;
    case DeleteAllPages:
      xsPDF.deleteAllPages();
      break;
    case LastLineFullJustified:
      xsPDF.setLastJustifiedLineRightAligned(true);
      break;
    case LastLineLeftAligned:
      xsPDF.setLastJustifiedLineRightAligned(false);
      break;
    case SingleFullPageColumn:
      currentPageSize = xsPDF.getPageSize();
      double width = currentPageSize.width / currentUnitFactor;
      double height = currentPageSize.height / currentUnitFactor;
      double margin = Math.min(width, height) / 20.0;
      xsPDF.addColumn(0, 0, width, height, null, margin);
      break;
    }
    return i;
  }

  private int useContentEncoding(int i, XSContentEncoding parm) {
    xsPDF.setContentEncoding(parm);
    return i;
  }

  private int useStringForPrinting(int i, String parm) {
    xsPDF.print(parm);
    return i;
  }

  private Double getIfNumeric(Object parm) {
    if (parm instanceof Double) {
      return (Double) parm;
    }
    if (parm instanceof Float) {
      return (double) (Float) parm;
    }
    if (parm instanceof Integer) {
      return (double) (Integer) parm;
    }
    if (parm instanceof Short) {
      return (double) (Short) parm;
    }
    if (parm instanceof Byte) {
      return (double) (Byte) parm;
    }
    return null;
  }
}
